// 实现获取下一个排列的函数，算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

// 如果不存在下一个更大的排列，则将数字重新排列成最小的排列（即升序排列）。

// 必须原地修改，只允许使用额外常数空间。

// 以下是一些例子，输入位于左侧列，其相应输出位于右侧列。
// 1,2,3 → 1,3,2
// 3,2,1 → 1,2,3
// 1,1,5 → 1,5,1

#include "stdc++.h"

/*
这道题让我们求下一个排列顺序，有题目中给的例子可以看出来，如果给定数组是降序，
则说明是全排列的最后一种情况，则下一个排列就是最初始情况，可以参见之前的博客 Permutations 全排列。
我们再来看下面一个例子，有如下的一个数组

1　　2　　7　　4　　3　　1

下一个排列为：

1　　3　　1　　2　　4　　7

那么是如何得到的呢，我们通过观察原数组可以发现，如果从末尾往前看，数字逐渐变大，
到了2时才减小的，然后我们再从后往前找第一个比2大的数字，是3，那么我们交换2和3，
再把此时3后面的所有数字转置一下即可，步骤如下：

1　　2　　7　　4　　3　　1

1　　2　　7　　4　　3　　1

1　　3　　7　　4　　2　　1

1　　3　　1　　2　　4　　7

时间复杂度：O(n)
空间复杂度：O(1)
*/
class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int i = n - 2;
        int j = n - 1;
        // 从后往前找到第一个升序
        while (i >= 0 && nums[i] >= nums[i+1]) --i;
        if (i >= 0) {
            // 从后往前找到第一个比numd[i]大的数
            while (nums[j] <= nums[i]) --j;
            swap(nums[i], nums[j]);
        }
        reverse(nums.begin() + i + 1, nums.end());
    }
};

#include "stdc++.h"

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int i = n - 2;
        // 1. 从后往前扫描找第一个升序对a[i] < a[i+1]，此时[i+1, n)必然是降序
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            --i;
        }
        // 2. 如果找到了顺序对，那么在区间[i+1, n)中从后往前找第一个大于a[i]的元素
        if (i >= 0) {
            int j = n - 1;
            while (j >= i && nums[i] >= nums[j]) {
                --j;
            }
            swap(nums[i], nums[j]);
        }
        // 3. 翻转区间[i+1, n)
        reverse(nums.begin() + i + 1, nums.end());
    }
};